// ignore_for_file: non_constant_identifier_names, constant_identifier_names

import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:ui' as ui;

class MyWidget extends StatefulWidget {
  const MyWidget({super.key});

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class OffsetTween extends Tween<Offset?> {
  OffsetTween({super.begin, super.end});

  @override
  Offset? lerp(double t) => Offset.lerp(begin, end, t);
}

class _MyWidgetState extends State<MyWidget>
    with SingleTickerProviderStateMixin {
  ui.Image? _image;
  Offset position = const Offset(400, 700);
  Offset paintUpdatePosition = Offset.zero;
  Future<ui.Image> loadNetImage(String path) async {
    final data = await NetworkAssetBundle(Uri.parse(path)).load(path);
    final bytes = data.buffer.asUint8List();
    final ui.Image image = await decodeImageFromList(bytes);
    return image;
  }

  final defaultWidth = 400;
  final defaultHeight = 700;
  ViewPointLocation _type = ViewPointLocation.STYLE_LOWER_RIGHT;
  bool _cOutTag = false;
  AnimationController? controller;
  Animation<Offset?>? animation;
  CurvedAnimation? curve;

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
    controller?.dispose();
    curve?.dispose();
  }

  void _nextScheduleAnimation(Offset start, ViewPointLocation type) {
    controller?.stop();
    controller ??= AnimationController(
        duration: const Duration(milliseconds: 400), vsync: this);
    curve ??= CurvedAnimation(parent: controller!, curve: Curves.easeIn);
    Offset end;
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      end = Offset(-defaultWidth.toDouble(), 1);
    } else if (type == ViewPointLocation.STYLE_LOWER_RIGHT) {
      end = Offset(-defaultWidth.toDouble(), defaultHeight.toDouble() - 1);
    } else {
      end = Offset(-defaultWidth.toDouble(), start.dy);
    }
    controller?.reset();
    final tween = OffsetTween(begin: start, end: end);
    animation = tween.animate(controller!);
    animation!.addListener(() {
      var offset = animation!.value!;
      updatePostion(offset, true, true);
    });
    controller?.forward();
  }

  void _lastScheduleAnimation() {
    controller?.stop();
    controller ??= AnimationController(
        duration: const Duration(milliseconds: 500), vsync: this);
    curve ??= CurvedAnimation(parent: controller!, curve: Curves.easeIn);
    final y = defaultHeight.toDouble() / 2.0;
    Offset end = Offset(-defaultWidth.toDouble(), y);
    controller?.reset();
    final tween =
        OffsetTween(begin: end, end: Offset(defaultWidth.toDouble(), y));
    animation = tween.animate(controller!);
    animation!.addListener(() {
      var offset = animation!.value!;
      updatePostion(offset, true, true);
    });
    controller?.forward();
  }

  void _recoverScheduleAnimation(Offset start) {
    controller?.stop();
    controller ??= AnimationController(
        duration: const Duration(milliseconds: 400), vsync: this);
    curve ??= CurvedAnimation(parent: controller!, curve: Curves.easeIn);
    Offset end;
    if (_type == ViewPointLocation.STYLE_TOP_RIGHT) {
      end = Offset(defaultWidth.toDouble(), 0);
    } else {
      end = Offset(defaultWidth.toDouble(), defaultHeight.toDouble());
    }

    controller?.reset();
    final tween = OffsetTween(begin: start, end: end);
    animation = tween.animate(controller!);
    animation!.addListener(() {
      var offset = animation!.value!;
      updatePostion(offset, true);
    });
    controller?.forward();
  }

  void updatePostion(Offset offset, [bool move = false, bool cOutTag = false]) {
    print("offset=$offset $move");
    ViewPointLocation type1 = _type;
    if (!move) {
      type1 = loadType(offset);
    }
    if ((offset != position || type1 != _type) && mounted) {
      setState(() {
        position = offset;
        _cOutTag = cOutTag;
        _type = type1;
      });
    }
  }

  ViewPointLocation loadType(Offset offset) {
    var size = MediaQuery.sizeOf(context);
    double width = defaultWidth.toDouble();
    double height = defaultHeight.toDouble();
    var x = offset.dx;
    var y = offset.dy;
    if (x <= width / 3) {
      //左
      return ViewPointLocation.STYLE_LEFT;
    } else if (x > width / 3 && y <= height / 3) {
      //上
      return ViewPointLocation.STYLE_TOP_RIGHT;
    } else if (x > width * 2 / 3 && y > height / 3 && y <= height * 2 / 3) {
      //右
      return ViewPointLocation.STYLE_RIGHT;
    } else if (x > width / 3 && y > height * 2 / 3) {
      //下
      return ViewPointLocation.STYLE_LOWER_RIGHT;
    } else if (x > width / 3 &&
        x < width * 2 / 3 &&
        y > height / 3 &&
        y < height * 2 / 3) {
      //中
      return ViewPointLocation.STYLE_MIDDLE;
    } else {
      return ViewPointLocation.STYLE_LOWER_RIGHT;
    }
  }

  final double MIN_SCROLL_TO_NEXT = 10;
  Offset? _dwonPoint;
  Offset? _lastPoint;
  bool? nextActionTag;
  bool _clickTag = false;
  int i = 0;
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Container(
        color: Colors.transparent,
        child: GestureDetector(
          behavior: HitTestBehavior.opaque,
          onTapDown: (details) {
            _initAnimationState(details.localPosition);
            print("onTapDown ${i++}--_lastPoint=$_dwonPoint");
            // updatePostion(details.localPosition);
          },
          onTap: () {
            print("点击${i++}");
            var type = loadType(_dwonPoint!);
            if (type == ViewPointLocation.STYLE_MIDDLE) {
              // 中间 菜单点击
            } else if (type == ViewPointLocation.STYLE_LEFT) {
              _type = type;
              // 左边点击
              _lastScheduleAnimation();
            } else {
              _type = type;
              // 右边点击
              // 起始点--模拟滑动起始点-->重新计算获取a点坐标
              _clickTag = true;
              updatePostion(_dwonPoint!, true);
              /* Future.delayed(const Duration(milliseconds: 10), () {
                // 获取painter 优化后的坐标点 a点
                _nextScheduleAnimation(paintUpdatePosition, type);
              }); */
            }
          },
          onTapCancel: () {
            _initAnimationState(null);
            _resetPointState();
          },
          onHorizontalDragStart: (details) {
            final point = details.localPosition;
            _initAnimationState(point);
            print("onHorizontalDragStart ${i++}");
            updatePostion(point);
          },
          onHorizontalDragUpdate: (details) {
            print("onHorizontalDragUpdate ${i++}");
            final point = details.localPosition;
            if (nextActionTag == null) {
              final cha = point.dx - (_lastPoint?.dx ?? 0);
              if (cha < 0) {
                // 向左滑 趋势下一页
                nextActionTag = true;
              } else {
                nextActionTag = false;
                // 向右滑 趋势上一页
              }
            }
            _lastPoint = point;
            updatePostion(point, true);
          },
          onHorizontalDragEnd: (details) {
            final point = details.localPosition;
            final scrollX = point.dx - (_dwonPoint?.dx ?? 0);
            if (scrollX < 0) {
              if ((-scrollX) < MIN_SCROLL_TO_NEXT) {
                // 滑动距离不够
                // 恢复原状
                _recoverScheduleAnimation(paintUpdatePosition);
              } else {
                // 下一页；
                _nextScheduleAnimation(paintUpdatePosition, _type);
              }
            } else {
              if (_type == ViewPointLocation.STYLE_TOP_RIGHT ||
                  _type == ViewPointLocation.STYLE_LOWER_RIGHT) {
                // 边角滑动 向右滑动 全部恢复原状，不翻页
                _recoverScheduleAnimation(paintUpdatePosition);
              } else {
                // 上一页 内容已经切换 直接恢复原状就行
                _recoverScheduleAnimation(paintUpdatePosition);
              }
            }

            _resetPointState();
          },
          child: SizedBox(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: CustomPaint(
              size: const Size(400, 700),
              painter: MyCustomPainter(
                type: _type,
                pointA: position,
                cOutTag: _cOutTag,
                defaultWidth: defaultWidth,
                defaultHeight: defaultHeight,
                onUpdatePointA: (offset) {
                  paintUpdatePosition = offset;
                  if (_clickTag) {
                    _clickTag = false;
                    _nextScheduleAnimation(paintUpdatePosition, _type);
                  }
                },
              ),
            ),
          ),
        ),
      ),
    );
  }

  void _initAnimationState(Offset? offset) {
    controller?.stop();
    _cOutTag = false;
    _dwonPoint = offset;
    _lastPoint = offset;
  }

  void _resetPointState() {
    _dwonPoint = null;
    nextActionTag = null;
    _lastPoint = null;
  }
}

class MyPoint {
  double x;
  double y;

  MyPoint(this.x, this.y);

  @override
  String toString() {
    return "x=$x, y=$y";
  }
}

enum ViewPointLocation {
  /// 击左边区域
  STYLE_LEFT,

  /// 点击右边区域
  STYLE_RIGHT,

  /// 点击中间区域
  STYLE_MIDDLE,

  /// f点在右上角
  STYLE_TOP_RIGHT,

  /// f点在右下角
  STYLE_LOWER_RIGHT,

  /// 初始化
  STYLE_INIT
}

const ATxt =
    '''1990年大年初五，四处张灯结彩，年味还比较浓厚。深夜，一辆大吉普警车从川北县城急驶而过。凌晨时分，警车停在距离渠江火车站一里开外的地方，没关车灯，川北县周镇派出所副所长刘开义，脸青面黑地从驾驶室走下来，拉开后车门，厉声喝道：“下来吧！”原文来~自于塔读小~说APP，~更多.免费*好书请下载塔~读-小说APP。身高175，身材偏瘦的肖凡拿着一个背包，从后座下车，唯唯诺诺走到刘开义身边。看到身边瑟瑟发抖的肖凡，刘开义掏出一包不带过滤嘴的翡翠，从烟包里抽出两支，丢了一支给肖凡，然后自个点上，重重地吸上几口，呵斥道：“你说你这个混小子，跟老李头学点拳脚，下手就不知道个轻重，目前情况是：对方两人开瓢，一个脑震荡，一个还有多处骨折，现在都躺在医院。”肖凡颓废地在警车边蹲了下来，埋头抽着闷烟，一直不敢说话。刘开义叹了口气，摇了摇头，放低了一些音量，“对方是食品公司经理的儿子和商业局副书记的儿子，那俩小子更混球，一天到处惹是生非不说，耍得没事，还摸到小媳妇钩子上去了。你也算见义勇为，但是下手也要有个轻重啊！如果赔付最少几大千，还要负法律责任，你家的情况，你自己又不是不清楚。一直比较孝顺、明事理、懂礼貌的孩子，怎么忽然就犯浑啊？还好没死人，赶紧出去躲一阵子，时间久了，到时候你挣到钱，我在帮你周旋一下，赔点钱私下协商，把事情处理了。”说完，刘开义丢掉叼在嘴里抽了半支的香烟，解开警服的上衣口袋，掏出三十元钱和一张写好的纸条，塞进肖凡手里，有些溺爱地摸了摸他的头，“事情已经出了，别想太多，在外要注意安全，别再惹事，纸条上是我乡下侄女谢燕的地址，她在广东东莞打工，听说工资蛮高，你小子没地方去，可以去这里，这钱是我的小金库，只有这么多，当叔的也只能帮你到这里，''';
const NextTxt =
    '''一直往前走，一里多地就是火车站，你走吧！”肖凡起身，看着眼前责备中充满关爱的老街坊，没有说话，双腿扑通一声跪在地上，对着刘叔重重地磕了三个响头，转身朝渠江火车站走去！看着远去的背影，刘开义从兜里掏出烟点上，“警察放走肇事者，而且还是亲自护送，到底是对是错？自己是凭本心做事，老街坊，谁家马桶被“盗”，派出所都知道的年代，这小子从小就特别懂事，热心，好助人，从不惹事，不想他因为乐于助人进牢房，毁了一生........”塔读小说，无广&gt;告^在线免。费阅读！........大年初六下午3点55分，惊慌失措的肖凡，登上由渠江开往广州的火车。车厢核载108员，现实车厢里旅客已超出一倍还多，超员的车厢除座位之外，每一个犄角旮旯也挤满或站、坐、趟的人，WC门口也是站岗的人，一人上WC，要挪动一群人，才能打开WC门。列车驶出渠江站半个小时后，肖凡紧张的心有些松懈，蹲在车厢中间，打着盹。“查票了，查票了，所有人把车票拿到手里，开始验票。”拥挤的车厢，乱哄哄的嘈杂人群，女列车员费力在人群中挪动，一边嘶喊，完全没点女性的温柔。听到查票，肖凡身边一位矮个子男子灵活地趴下，钻进三人座的座位下面。一行座位，就一个三排座，一个两排座。肖凡迅速钻进两排座下，身躯弯曲，身高175，在两排座下始终长了一点，头在座位下，屁股露出了座位。身上就那点散碎银子，就想逃票。首发：塔&gt;-读小说列车员走近座位，看见有屁股露在座位外，用脚踢了踢他的屁股，提示道：“出来查票，出来查票？”肖凡从座位下钻出来，有些惊慌，像小媳妇撒娇，害羞地说道：“我没有票。”列车员调侃地训斥道：“躲到座位下逃票，你也藏好点啊，顾头不顾尾，把钩子（屁股）露在外面，瞎子都能看到，马上补票，车票26元，逃票按票价的百分之五十处罚元共计''';

class MyCustomPainter extends CustomPainter {
  Paint pointPaint; //绘制各标识点的画笔
  Paint bgPaint; //背景画笔
  Paint pathAPaint; //绘制A区域画笔
  Paint pathCPaint; //绘制C区域画笔
  Paint pathBPaint; //绘制B区域画笔
  MyPoint a = MyPoint(0, 0),
      f = MyPoint(0, 0),
      g = MyPoint(0, 0),
      e = MyPoint(0, 0),
      h = MyPoint(0, 0),
      c = MyPoint(0, 0),
      j = MyPoint(0, 0),
      b = MyPoint(0, 0),
      k = MyPoint(0, 0),
      d = MyPoint(0, 0),
      i = MyPoint(0, 0);

  int defaultWidth; //默认宽度
  int defaultHeight; //默认高度
  int viewWidth;
  int viewHeight;

  Path pathA;
  double lPathAShadowDis = 0;
  double rPathAShadowDis = 0;
  final Offset pointA;
  final bool cOutTag;
  final ViewPointLocation type;
  final Path canvanPath;
  final void Function(Offset offset) onUpdatePointA;
  MyCustomPainter({
    this.defaultWidth = 400,
    this.defaultHeight = 700,
    required this.type,
    required this.cOutTag,
    required this.onUpdatePointA,
    this.pointA = const Offset(0, 0),
  })  : viewWidth = defaultWidth,
        viewHeight = defaultHeight,
        pointPaint = Paint()
          ..color = Colors.black
          ..isAntiAlias = true,
        pathAPaint = Paint()
          ..color = Colors.green
          ..isAntiAlias = true,
        bgPaint = Paint()
          ..color = Colors.white
          ..isAntiAlias = true,
        pathCPaint = Paint()
          ..color = const Color.fromARGB(255, 255, 247, 10)
          ..isAntiAlias = true,
        pathBPaint = Paint()
          ..color = Colors.blue
          ..isAntiAlias = true,
        pathA = Path(),
        canvanPath = Path()
          ..moveTo(0, 0)
          ..lineTo(defaultWidth.toDouble(), 0)
          ..lineTo(defaultWidth.toDouble(), defaultHeight.toDouble())
          ..lineTo(0, defaultHeight.toDouble())
          ..lineTo(0, 0),
        assert(defaultWidth > 0 && defaultHeight > 0, "必须大于0") {
    canvanPath.close();
    updateTouchPoint(pointA.dx, pointA.dy, type);
  }

  void updateTouchPoint(double x, double y, ViewPointLocation type) {
    a.x = x;
    a.y = y;
    switch (type) {
      case ViewPointLocation.STYLE_TOP_RIGHT:
        f.x = viewWidth.toDouble();
        f.y = 0;
        a.y = Math.abs(a.y);
        calcPointsXY(a, f);
        if (calcPointCX(a, f) < 0) {
          //如果c点x坐标小于0则重新测量a点坐标
          calcPointAByTouchPoint();
          calcPointsXY(a, f);
        }
        break;
      case ViewPointLocation.STYLE_LEFT:
      case ViewPointLocation.STYLE_MIDDLE:
      case ViewPointLocation.STYLE_RIGHT:
        a.y = viewHeight - 2;
        f.x = viewWidth.toDouble();
        f.y = viewHeight.toDouble();
        calcPointsXY(a, f);
        // postInvalidate();
        break;
      case ViewPointLocation.STYLE_LOWER_RIGHT:
        f.x = viewWidth.toDouble();
        f.y = viewHeight.toDouble();
        a.y = a.y > viewHeight ? (viewHeight + viewHeight - a.y) : a.y;
        calcPointsXY(a, f);
        if (calcPointCX(a, f) < 0) {
          //如果c点x坐标小于0则重新测量a点坐标
          calcPointAByTouchPoint();
          calcPointsXY(a, f);
        }
        // postInvalidate();
        break;
      default:
        break;
    }
    onUpdatePointA(Offset(a.x, a.y));
  }

  void calcPointAByTouchPoint() {
    // print("c.x=${c.x}");
    double w0 = viewWidth - c.x;
    double w1 = Math.abs(f.x - a.x);
    double w2 = viewWidth * w1 / w0;
    a.x = Math.abs(f.x - w2);

    double h1 = Math.abs(f.y - a.y);
    double h2 = w2 * h1 / w1;
    a.y = Math.abs(f.y - h2);
  }

  double calcPointCX(MyPoint a, MyPoint f) {
    if (cOutTag) return 11; // 大于0即可
    MyPoint g, e;
    g = MyPoint(0, 0);
    e = MyPoint(0, 0);
    g.x = (a.x + f.x) / 2;
    g.y = (a.y + f.y) / 2;

    e.x = g.x - (f.y - g.y) * (f.y - g.y) / (f.x - g.x);
    e.y = f.y;

    return e.x - (f.x - e.x) / 2;
  }

  @override
  bool? hitTest(Offset position) {
    return false;
  }

  void calcPointsXY(MyPoint a, MyPoint f) {
    if (a.x <= 0 && a.y <= 0) {
      f = MyPoint(0, 0);
      g = MyPoint(0, 0);
      e = MyPoint(0, 0);
      h = MyPoint(0, 0);
      c = MyPoint(0, 0);
      j = MyPoint(0, 0);
      b = MyPoint(0, 0);
      k = MyPoint(0, 0);
      d = MyPoint(0, 0);
      i = MyPoint(0, 0);
      return;
    }
    // a.x = min(a.x, viewWidth - 10);

    g.x = (a.x + f.x) / 2;
    g.y = (a.y + f.y) / 2;
    e.x = g.x - (f.y - g.y) * (f.y - g.y) / (f.x - g.x);
    e.y = f.y;

    h.x = f.x;
    h.y = g.y - (f.x - g.x) * (f.x - g.x) / (f.y - g.y);

    c.x = e.x - (f.x - e.x) / 2;
    c.y = f.y;

    j.x = f.x;
    j.y = h.y - (f.y - h.y) / 2;

    b = getIntersectionPoint(a, e, c, j);
    k = getIntersectionPoint(a, h, c, j);

    d.x = (c.x + 2 * e.x + b.x) / 4;
    d.y = (2 * e.y + c.y + b.y) / 4;

    i.x = (j.x + 2 * h.x + k.x) / 4;
    i.y = (2 * h.y + j.y + k.y) / 4;

    //计算d点到直线ae的距离
    double lA = a.y - e.y;
    double lB = e.x - a.x;
    double lC = a.x * e.y - e.x * a.y;
    lPathAShadowDis = Math.abs((lA * d.x + lB * d.y + lC) / Math.hypot(lA, lB));
    double rA = a.y - h.y;
    double rB = h.x - a.x;
    double rC = a.x * h.y - h.x * a.y;
    rPathAShadowDis = Math.abs((rA * i.x + rB * i.y + rC) / Math.hypot(rA, rB));
  }

  /// 计算两线段相交点坐标
  MyPoint getIntersectionPoint(
    MyPoint lineOne_My_pointOne,
    MyPoint lineOne_My_pointTwo,
    MyPoint lineTwo_My_pointOne,
    MyPoint lineTwo_My_pointTwo,
  ) {
    double x1, y1, x2, y2, x3, y3, x4, y4;
    x1 = lineOne_My_pointOne.x;
    y1 = lineOne_My_pointOne.y;
    x2 = lineOne_My_pointTwo.x;
    y2 = lineOne_My_pointTwo.y;
    x3 = lineTwo_My_pointOne.x;
    y3 = lineTwo_My_pointOne.y;
    x4 = lineTwo_My_pointTwo.x;
    y4 = lineTwo_My_pointTwo.y;

    double pointX =
        ((x1 - x2) * (x3 * y4 - x4 * y3) - (x3 - x4) * (x1 * y2 - x2 * y1)) /
            ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4));
    double pointY =
        ((y1 - y2) * (x3 * y4 - x4 * y3) - (x1 * y2 - x2 * y1) * (y3 - y4)) /
            ((y1 - y2) * (x3 - x4) - (x1 - x2) * (y3 - y4));

    return MyPoint(pointX, pointY);
  }

  // List<Color> gradientColors = [Color.fromARGB(255, 218, 218, 218), Color.fromARGB(100, 218, 218, 218)]; //渐变颜色数组
  // List<Color> gradientColors = [Color(0xff111111), Color(0x00111111)]; //渐变颜色数组

  Picture loadAPicture(String context) {
    PictureRecorder recorder = PictureRecorder();
    Canvas canvas = Canvas(recorder);
    // canvas.drawColor(pathAPaint.color, BlendMode.srcATop);
    canvas.clipRect(
        Rect.fromLTRB(0, 0, viewWidth.toDouble(), viewHeight.toDouble()));
    canvas.drawText(ATxt, 0, 0, Colors.white);
    Picture picture = recorder.endRecording();
    return picture;
  }

  @override
  void paint(Canvas canvas, Size size) {
    canvas.clipRect(
        Rect.fromLTRB(0, 0, viewWidth.toDouble(), viewHeight.toDouble()));
    canvas.drawColor(Colors.yellow, BlendMode.src);
    if (a.x != viewWidth && a.y != viewHeight) {
      /// B区域
      var pathb = getPathB();
      canvas.drawPath(pathb, pathBPaint);
      canvas.drawText(NextTxt, 0, 0);

      // 绘制b区上的阴影
      canvas.save();
      var paint = Paint()..isAntiAlias = true;
      drawPathBShadow(canvas, paint);
      canvas.restore();

      // A区域内容
      // var picture = loadAPicture(ATxt);

      /// C区域
      var pathc = getPathC();
      pathc = Path.combine(PathOperation.intersect, pathc, canvanPath);
      canvas.drawPath(pathc, pathCPaint);
      // c 内容
      makeCContent(canvas, pathc);
      // c 阴影
      canvas.save();
      canvas.clipPath(pathc);
      drawPathCShadow(canvas, paint);
      canvas.restore();

      /// A 区域
      pathAPaint.blendMode = BlendMode.srcATop;
      // canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height),Paint());
      Path patha;
      if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
        patha = getPathAFromTopRight();
      } else {
        patha = getPathAFromLowerRight();
      }
      canvas.drawPath(patha, pathAPaint);

      canvas.save();
      canvas.clipPath(patha);
      canvas.drawText(ATxt, 0, 0, Colors.white);
      // canvas.drawPicture(picture);
      if (type == ViewPointLocation.STYLE_LEFT ||
          type == ViewPointLocation.STYLE_MIDDLE ||
          type == ViewPointLocation.STYLE_RIGHT) {
        canvas.save();
        drawPathAHorizontalShadow(canvas, paint);
        canvas.restore();
      } else {
        canvas.save();
        drawPathALeftShadow1(canvas, paint);
        canvas.restore();

        canvas.save();
        drawPathARightShadow1(canvas);
        canvas.restore();
      }
      canvas.restore();
    } else {
      pathA.reset();
      pathA.moveTo(0, 0);
      pathA.lineTo(0, viewHeight.toDouble());
      pathA.lineTo(viewWidth.toDouble(), viewHeight.toDouble());
      pathA.lineTo(viewWidth.toDouble(), 0);
      pathA.close();
      canvas.drawPath(pathA, pathAPaint);
      canvas.drawText(ATxt, 0, 0, Colors.white);
    }
    // drawPointText(canvas);
  }

  void makeCContent(Canvas canvas, Path pathc /* , Picture picture */) {
    canvas.save();
    canvas.clipPath(pathc);
    canvas.save();
    // var e = d;
    double bRadians = Math.atan21(Math.abs(f.x - e.x), Math.abs(h.y - f.y));
    var radians = 2 * pi - 2 * bRadians;

    var mMatrix = Matrix4.translationValues(e.x, e.y, 0);
    // mMatrix.rotationY(pi);
    mMatrix.rotateY(pi);
    mMatrix.rotateZ(
        radians * (type == ViewPointLocation.STYLE_TOP_RIGHT ? -1 : 1));
    canvas.transform(mMatrix.storage);
    // canvas.translate(-e.x, -e.y);
    // canvas.drawPicture(picture);
    var painter = TextPainter(
      text: const TextSpan(
          text: ATxt,
          style: TextStyle(
            fontSize: 16,
            color: Colors.grey,
          )),
      textDirection: TextDirection.ltr,
    )..layout(maxWidth: viewWidth.toDouble());
    // var size = painter.size;
    painter.paint(
      canvas,
      Offset(
        0 - e.x,
        0 - e.y,
      ),
    );
    canvas.restore();
    canvas.restore();
  }

  void drawPointText(Canvas canvas) {
    //绘制各标识点
    canvas.drawText("a", a.x, a.y);
    canvas.drawText("f", f.x, f.y);
    canvas.drawText("g", g.x, g.y);

    canvas.drawText("e", e.x, e.y);
    canvas.drawText("h", h.x, h.y);

    canvas.drawText("c", c.x, c.y);
    canvas.drawText("j", j.x, j.y);

    canvas.drawText("b", b.x, b.y);
    canvas.drawText("k", k.x, k.y);

    canvas.drawText("d", d.x, d.y);
    canvas.drawText("i", i.x, i.y);
  }

  @override
  bool shouldRepaint(covariant MyCustomPainter oldDelegate) {
    return oldDelegate.type != type || oldDelegate.pointA != pointA;
  }

  Path getPathAFromLowerRight() {
    pathA.moveTo(0, 0);
    pathA.lineTo(0, viewHeight.toDouble()); //移动到左下角
    pathA.lineTo(c.x, c.y); //移动到c点
    // pathA.quadTo(e.x, e.y, b.x, b.y); //从c到b画贝塞尔曲线，控制点为e
    pathA.quadraticBezierTo(e.x, e.y, b.x, b.y); //从c到b画贝塞尔曲线，控制点为e
    pathA.lineTo(a.x, a.y); //移动到a点
    pathA.lineTo(k.x, k.y); //移动到k点
    pathA.quadraticBezierTo(h.x, h.y, j.x, j.y); //从k到j画贝塞尔曲线，控制点为h
    pathA.lineTo(viewWidth.toDouble(), 0); //移动到右上角
    pathA.close(); //闭合区域
    return pathA;
  }

  Path getPathAFromTopRight() {
    pathA.reset();
    pathA.lineTo(c.x, c.y); //移动到c点
    pathA.quadraticBezierTo(e.x, e.y, b.x, b.y); //从c到b画贝塞尔曲线，控制点为e
    pathA.lineTo(a.x, a.y); //移动到a点
    pathA.lineTo(k.x, k.y); //移动到k点
    pathA.quadraticBezierTo(h.x, h.y, j.x, j.y); //从k到j画贝塞尔曲线，控制点为h
    pathA.lineTo(viewWidth.toDouble(), viewHeight.toDouble()); //移动到右下角
    pathA.lineTo(0, viewHeight.toDouble()); //移动到左下角
    pathA.close();
    return pathA;
  }

  Path getPathC() {
    final pathC = Path();
    pathC.moveTo(i.x, i.y); //移动到i点
    pathC.lineTo(d.x, d.y); //移动到d点
    pathC.lineTo(b.x, b.y); //移动到b点
    pathC.lineTo(a.x, a.y); //移动到a点
    pathC.lineTo(k.x, k.y); //移动到k点
    pathC.close(); //闭合区域
    return pathC;
  }

  Path getPathB() {
    final pathB = Path();
    pathB.reset();
    pathB.lineTo(0, viewHeight.toDouble()); //移动到左下角
    pathB.lineTo(viewWidth.toDouble(), viewHeight.toDouble()); //移动到右下角
    pathB.lineTo(viewWidth.toDouble(), 0); //移动到右上角
    pathB.close(); //闭合区域
    return pathB;
  }

  void drawPathBShadow(Canvas canvas, Paint paint) {
    int deepColor = 0xff111111; //为了让效果更明显使用此颜色代码，具体可根据实际情况调整
//        int deepColor = 0x55111111;
    int lightColor = 0x00111111;
    List<Color> gradientColors = [Color(deepColor), Color(lightColor)]; //渐变颜色数组

    int deepOffset = 0; //深色端的偏移值
    int lightOffset = 0; //浅色端的偏移值
    double aTof = Math.hypot((a.x - f.x), (a.y - f.y)); //a到f的距离
    double viewDiagonalLength =
        Math.hypot(viewWidth.toDouble(), viewHeight.toDouble()); //对角线长度

    double left;
    double right;
    double top = c.y;
    double bottom = (viewDiagonalLength + c.y);
    // ..shader = LinearGradient(colors: gradientColors);

    LinearGradient linearGradient;
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      //f点在右上角
      //从左向右线性渐变
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
      );
      left = (c.x - deepOffset); //c点位于左上角
      right = (c.x + aTof / 5 + lightOffset);
    } else {
      //从右向左线性渐变
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerRight,
        end: Alignment.centerLeft,
      );
      left = (c.x - aTof / 5 - lightOffset); //c点位于左下角
      right = (c.x + deepOffset);
    }
    paint.shader = linearGradient.createShader(
        Rect.fromLTRB(left, top, right, bottom).translate(-c.x, -c.y));
    // gradientDrawable.setBounds(left, top, right, bottom); //设置阴影矩形

    double rotateDegrees = Math.atan21(f.y - h.y, f.x - e.x); //旋转角度
    print("rotateDegrees=${rotateDegrees.toDegrees()}");
    canvas.translate(c.x, c.y);
    canvas.rotate(-pi / 2 - rotateDegrees); //以c为中心点旋转
    canvas.drawRect(
        Rect.fromLTRB(left, top, right, bottom).translate(-c.x, -c.y), paint);
  }

  /// 绘制C区域阴影，阴影左浅右深
  void drawPathCShadow(Canvas canvas, Paint paint) {
    int deepColor = 0xa1111111; //为了让效果更明显使用此颜色代码，具体可根据实际情况调整
//        int deepColor = 0x55333333;
    int lightColor = 0x00333333;
    List<Color> gradientColors = [Color(deepColor), Color(lightColor)]; //渐变颜色数组

    int deepOffset = 1; //深色端的偏移值
    int lightOffset = -10; //浅色端的偏移值
    double viewDiagonalLength =
        Math.hypot(viewWidth.toDouble(), viewHeight.toDouble()); //view对角线长度
    double midpoint_ce = (c.x + e.x) / 2; //ce中点
    double midpoint_jh = (j.y + h.y) / 2; //jh中点
    double minDisToControlPoint = min(
        Math.abs(midpoint_ce - e.x), Math.abs(midpoint_jh - h.y)); //中点到控制点的最小值

    double left;
    double right;
    double top = c.y;
    double bottom = (viewDiagonalLength + c.y);
    LinearGradient linearGradient;
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerRight,
        end: Alignment.centerLeft,
      );
      left = (c.x - lightOffset);
      right = (c.x + minDisToControlPoint + deepOffset);
    } else {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
      );
      left = (c.x - minDisToControlPoint - deepOffset);
      right = (c.x + lightOffset);
    }
    // gradientDrawable.setBounds(left, top, right, bottom);
    var rect = Rect.fromLTRB(left, top, right, bottom).translate(-c.x, -c.y);
    paint.shader = linearGradient.createShader(rect);
    double mDegrees = Math.atan21((f.x - e.x), (h.y - f.y));
    canvas.translate(c.x, c.y);
    canvas.rotate(-mDegrees);
    canvas.drawRect(rect, paint);
  }

  double drawPathARightShadow1(Canvas canvas) {
    int deepColor = 0x33333333;
    int lightColor = 0x00333333;
    List<Color> gradientColors = [Color(lightColor), Color(deepColor)]; //渐变颜色数组
    double viewDiagonalLength =
        Math.hypot(viewWidth + 0.0, viewHeight + 0.0); //view对角线长度
    double left = a.x;
    left = a.x - lPathAShadowDis / 2;
    double right = left + viewDiagonalLength;
    double top;
    double bottom;

    // double bottom = (e.y + Math.hypot(e.x-a.x, e.y-a.y));
    LinearGradient linearGradient;
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.bottomCenter,
        end: Alignment.topCenter,
      );
      top = a.y;
      bottom = a.y + rPathAShadowDis / 2;
    } else {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
      );
      top = a.y - rPathAShadowDis / 2;
      bottom = a.y;
    }

    var paint = Paint()..isAntiAlias = true;
    var rect = Rect.fromLTRB(left, top, right, bottom).translate(-a.x, -a.y);
    double mDegrees = atan2(a.y - h.y, h.x - a.x);
    canvas.translate(a.x, a.y);
    // print("mDegrees=$mDegrees");
    canvas.rotate(-mDegrees);
    paint.shader = linearGradient.createShader(rect);
    var path = Path();
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      path.lineTo(rect.left, rect.bottom);
      path.lineTo(rect.right, rect.bottom);
      path.lineTo(rect.right, rect.top);
      path.lineTo(rect.left + lPathAShadowDis / 2, rect.top);
      path.lineTo(rect.left, rect.bottom);
    } else {
      path.moveTo(rect.left, rect.top);
      path.lineTo(rect.right, rect.top);
      path.lineTo(rect.right, rect.bottom);
      path.lineTo(rect.left + lPathAShadowDis / 2, rect.bottom);
      path.lineTo(rect.left, rect.top);
    }
    path.close();
    // canvas.drawPath(path, Paint()..color=Colors.red);
    canvas.clipPath(path);
    canvas.drawRect(rect, paint);

    return mDegrees;
  }

  void drawPathALeftShadow1(Canvas canvas, Paint paint) {
    int deepColor = 0x33333333;
    int lightColor = 0x00333333;
    List<Color> gradientColors = [Color(lightColor), Color(deepColor)]; //渐变颜色数组

    double left = a.x - lPathAShadowDis / 2;
    double right = a.x;
    double top;
    double bottom;
    // double bottom = (e.y + Math.hypot(e.x-a.x, e.y-a.y));
    var viewDiagonalLength = Math.hypot(a.x - e.x, a.y - e.y);
    LinearGradient linearGradient;
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
      );
      bottom = a.y + rPathAShadowDis / 2;
      top = bottom - viewDiagonalLength;
    } else {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
      );

      top = a.y - rPathAShadowDis / 2;
      bottom = top + viewDiagonalLength;
    }

    var rect = Rect.fromLTRB(left, top, right, bottom).translate(-a.x, -a.y);
    paint.shader = linearGradient.createShader(rect);
    double mDegrees = atan2((e.y - a.y), e.x - a.x);
    canvas.translate(a.x, a.y);
    // print("mDegrees = ${mDegrees.toDegrees()} ${(pi / 2).toDegrees()}");
    /*  if (mDegrees > pi / 2) {
      canvas.rotate(pi + mDegrees);
    } else {
      canvas.rotate(pi - mDegrees);
    } */

    Path mPath = Path();
    mPath.moveTo(a.x - lPathAShadowDis / 2, a.y - rPathAShadowDis / 2);
    double tag;
    var path = Path();
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      path.lineTo(rect.left, rect.bottom);
      path.lineTo(rect.right, rect.bottom - rPathAShadowDis / 2);
      path.lineTo(rect.right, rect.top);
      path.lineTo(rect.left, rect.top);
      path.lineTo(rect.left, rect.bottom);
      tag = 1;
    } else {
      path.moveTo(rect.left, rect.top);
      path.lineTo(rect.right, rect.top + rPathAShadowDis / 2);
      path.lineTo(rect.right, rect.bottom);
      path.lineTo(rect.left, rect.bottom);
      path.lineTo(rect.left, rect.top);
      tag = -1;
    }
    path.close();
    canvas.rotate(mDegrees + tag * pi / 2);
    canvas.clipPath(path);

    canvas.drawRect(rect, paint);
  }

  /// 绘制A区域左阴影
  void drawPathALeftShadow(Canvas canvas, Paint paint) {
    canvas.save();
    Path mPath = Path();
    mPath.moveTo(a.x - max(rPathAShadowDis, lPathAShadowDis) / 2, a.y);
    mPath.lineTo(d.x, d.y);
    mPath.lineTo(e.x, e.y);
    mPath.lineTo(a.x, a.y);
    mPath.close();
    canvas.clipPath(mPath);

    int deepColor = 0x33333333;
    int lightColor = 0x00333333;
    List<Color> gradientColors = [Color(lightColor), Color(deepColor)]; //渐变颜色数组

    double left;
    double right;
    double top = e.y;
    double bottom = (e.y + viewHeight);
    // double bottom = (e.y + Math.hypot(e.x-a.x, e.y-a.y));

    LinearGradient linearGradient;
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
      );
      left = (e.x - lPathAShadowDis / 2);
      right = (e.x);
    } else {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.centerRight,
        end: Alignment.centerLeft,
      );
      left = (e.x);
      right = (e.x + lPathAShadowDis / 2);
    }

    var rect = Rect.fromLTRB(left, top, right, bottom).translate(-e.x, -e.y);
    paint.shader = linearGradient.createShader(rect);
    double mDegrees = atan2((e.y - a.y), e.x - a.x);
    canvas.translate(e.x, e.y);
    print("mDegrees = ${mDegrees.toDegrees()} ${(pi / 2).toDegrees()}");
    /*  if (mDegrees > pi / 2) {
      canvas.rotate(pi + mDegrees);
    } else {
      canvas.rotate(pi - mDegrees);
    } */
    canvas.rotate(pi / 2 + mDegrees);
    canvas.drawRect(rect, paint);
    canvas.restore();
  }

  void drawPathARightShadow(Canvas canvas, Paint paint) {
    canvas.save();
    Path mPath = Path();
    mPath.moveTo(a.x - max(rPathAShadowDis, lPathAShadowDis) / 2, a.y);
    // mPath.lineTo(i.x,i.y);
    mPath.lineTo(h.x, h.y);
    mPath.lineTo(a.x, a.y);
    mPath.close();
    // canvas.clipPath(mPath);

    int deepColor = 0x33333333;
    int lightColor = 0x00333333;
    List<Color> gradientColors = [Color(deepColor), Color(lightColor)]; //渐变颜色数组
    double viewDiagonalLength =
        Math.hypot(viewWidth + 0.0, viewHeight + 0.0); //view对角线长度
    double left = h.x;
    double right = h.x + viewDiagonalLength * 10;
    double top;
    double bottom;
    // double bottom = (e.y + Math.hypot(e.x-a.x, e.y-a.y));

    LinearGradient linearGradient;
    if (type == ViewPointLocation.STYLE_TOP_RIGHT) {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.bottomCenter,
        end: Alignment.topCenter,
      );
      top = (h.y - rPathAShadowDis / 2);
      bottom = h.y;
    } else {
      linearGradient = LinearGradient(
        colors: gradientColors,
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
      );
      top = h.y;
      bottom = (h.y + rPathAShadowDis / 2);
    }

    var rect = Rect.fromLTRB(left, top, right, bottom).translate(-h.x, -h.y);
    double mDegrees = atan2(a.y - h.y, a.x - h.x);
    canvas.translate(h.x, h.y);
    canvas.rotate(mDegrees);
    paint.shader = linearGradient.createShader(rect);
    canvas.drawRect(rect, paint);
    canvas.restore();
    // paint.shader = linearGradient.createShader(Rect.fromLTWH(0, 300, rect.width, rect.bottom));
    // canvas.drawRect(Rect.fromLTWH(0, 300, rect.width, rect.bottom), paint);
    // canvas.drawRect(Rect.fromLTWH(0, 200, rect.width, rect.bottom), Paint()..color=Colors.yellow);
  }

  void drawPathAHorizontalShadow(Canvas canvas, Paint paint) {
    int deepColor = 0x44333333;
    int lightColor = 0x01333333;
    List<Color> gradientColors = [Color(lightColor), Color(deepColor)]; //渐变颜色数组
    LinearGradient linearGradient = LinearGradient(
      colors: gradientColors,
      begin: Alignment.centerLeft,
      end: Alignment.centerRight,
    );
    double maxShadowWidth = 30; //阴影矩形最大的宽度
    double left = a.x - min(maxShadowWidth, (rPathAShadowDis / 2));
    double right = a.x;
    double top = 0;
    double bottom = viewHeight.toDouble();
    var rect = Rect.fromLTRB(left, top, right, bottom).translate(-a.x, -a.y);
    double mDegrees = atan2(f.x - a.x, f.y - h.y);
    canvas.translate(a.x, a.y);
    canvas.rotate(mDegrees);
    paint.shader = linearGradient.createShader(rect);
    canvas.drawRect(rect, paint);
  }
}

extension MyCanvas on Canvas {
  void drawText(String text, double x, double y, [Color? color = Colors.red]) {
    if (!x.isNaN && !y.isNaN) {
      TextPainter(
        text: TextSpan(
            text: text,
            style: TextStyle(
              fontSize: 16,
              color: color,
            )),
        textDirection: TextDirection.ltr,
      )
        ..layout(maxWidth: 400)
        ..paint(this, Offset(x, y));
    }
  }
}

class Math {
  static double abs(double num) {
    return num.abs();
  }

  static double hypot(double a, double b) {
    return sqrt(a * a + b * b);
  }

  static double atan21(double a, double b) {
    print("a=$a, b=$b");
    return atan2(a, b);
  }

  static double toDegrees(double a) {
    return a.toDegrees();
  }
}

extension MyDouble on double {
  double toDegrees() {
    return this * 180 / pi;
  }
}

extension MyString on String {
  /// 半角转全角字符
  String toDBC(String input) {
    var c = input.codeUnits;
    var s = '';
    for (var i = 0; i < c.length; i++) {
      if (c[i] == 32) {
        // 半角空格
        s = s + String.fromCharCode(12288);
      } else if (c[i] < 127) {
        // 半角英文字符
        //如果前后为换行符，则不转换
        if (c[i] == 10) {
          s = s + String.fromCharCode(c[i]);
        } else {
          s = s + String.fromCharCode(c[i] + 65248);
        }
      } else {
        // 非半角字符
        s = s + String.fromCharCode(c[i]);
      }
    }
    return s;
  }
}
